In this episode, Leo talks with Jared Sorge of Xcoders about how they automate some of the components of their Xcode build and the tools they use.
An exploration of Apple business news and technology. We talk about how businesses can use new technology to empower their business and employees, from Leo Dion, founder of BrightDigit.
Leo: Welcome to another episode of Empower Apps. I'm your host, Leo Dion. Today, I'm joined by Jared Sorge. Hey, Jared, how's it going?
Jared: It's going pretty well. How are you, Leo?
Leo: Good. Thank you so much for coming on the show. I'm really excited to have a fellow podcaster. Jared, you host the Xcoders Podcast. What else do you do right now?
Jared: My day job is at Zulily. I'm in the Seattle area and that's where Zulily is based. Zulily is an online retailer and I'm an iOS engineer on what they call the core site and apps squad which is basically an infrastructure team that sits below all of our feature teams to help them get their jobs done more efficiently. I get to work on fun stuff like tooling, architecture, automation, and a lot of cool stuff like that.
Leo: We were chatting previously because you had a recent speaker that was also a guest Malin on talking about her experience with SwiftUI. Then, we got started talking about automation. I was like, “Ooh, automation. That’s my thing.” We’ve had guests on the show talk about continuous integration things like that but some of the stuff we'll talk about today I think we're both really passionate about what we're all developers who are kind of interested in automation at some point, right? But what do you think automation helps with when it comes to your typical iOS development team?
Jared: I think it can help you in your day-to-day workflow. One example is that before Zulilu I worked at Lyft. And on the first day at Lyft, they told me that they don't check in Xcode projects and that blew my mind. What they did was they used a tool to generate those Xcode projects from manifest files and that enabled a lot of flexibility in how you built the project. One thing that I've come to really like about this method is when you go and add a new target in Xcode itself. There's a lot of extra files and it is set up the way Xcode wants it to be set up, not the way that necessarily makes sense for your project. And adding some tooling on top of Xcode to suit the needs of your team or your project really can make development go faster. I implemented this actually at Zulily a couple of months ago where we are now generating our project programmatically. The amount of merge conflicts that we have is basically none because the project file would be the big source of churn. We'd have developers spending hours debugging merge conflicts between where the main branch and their feature branch and that just goes away. So this automation and tooling can really help reduce the amount of friction in the workflows of our developers and that's a lot of fun to see.
Leo: Yeah, Xcode projects are probably, besides Storyboards, are the biggest merge conflict issue folks deal with. What tooling did they use for generating that based on a manifest?
Jared: At Lyft I was introduced to XcodeGen and I still use that on some of my personal projects. But at Zulily I actually went with Tuist which is a slightly different philosophy than XcodeGen. Actually, it's quite a bit different if I'm being honest because these Tuist manifests are all done in Swift. It’s more akin to defining a Swift package manifest like you do in Swift Package Manager but they give you a module that you can fill out your own helper functions and methods so you can add a lot of niceties to your interfaces for how you actually create. They call them micro features. We're using the term modules. But it gives us the ability to really define and narrow down how these things are created to make it a lot easier for our developers.
Leo: So XcodeGen is typically YAML based, right?
Jared: Yeah. YAML or JSON.
Leo: I'm more familiar with XcodeGen. Actually, in one of the current clients they're using Tuist. How would you decide, like, it sounds in your personal projects you're using XcodeGen. How do you come to that decision that in this case XcodeGen is good but in this case Tuist might be better. The big thing for us at Zulily that at least led me down the Tuist path was support for test plans. We had implemented test plans in our iOS project probably a couple months prior and XcodeGen at least when we were looking at it didn't yet support test plans and I didn't want to just abandon them to do project generation. But Tuist does support them and they support them really well so that was the main thing that led me down that path. And then, as I started learning more about Tuist and some of its extra features it has stuff like building new modules or micro features right in so you can define your own templates. I think they call them stencils but it makes that super easy. Stuff at Lyft was previously bolted on and this extra tooling is built into Tuist which is really nice. They also have a feature called focus which I don't know if Lyft made that as part of Bazel or if it's part of Bazel that Lyft adopted. But the idea is that you would make your project focused on one or n number of modules. And the tooling would put together a project that has just those in the project and pre-compile everything down below so you're focused really just on the stuff that you care about. And everything else builds super-fast and it's really nice.
Leo: That's awesome. Yeah, because I think that's one of the things when you get to a larger company where being able to get faster builds like that are you know make it a lot easier.
We talked about the front end, not the front end but the beginning part of creating that Xcode project. How about when it comes to testing? What tools do you use to automate that?
Jared: Well, I mentioned we use test plans and that stitches together different scenarios. We have our pre-merge request test plan that we run before we create our merge request run GitLab so it's on merge request not pull request. And you can set up different scenarios that way. As far as other automation pieces that we have, we do use fastlane for making new builds, for making betas and submitting to the app store, and that kind of thing. We use for continuous integration, we have Jenkins setup, which I'm still learning about and isn't my favorite. I think we're going to be pivoting to GitLab CI here in the next month or so. That's a project I get to take on. Those are the main things that we use for automation at Zulily.
Leo: Yeah, I've known fastlane for years since I was an iOS developer and first starting out. But I was actually able to use it with the recent release of Heartwitch because they just supported independent watch apps now and hooked that up to GitLab CI. It was so awesome to be able to just automate that part of posting into the app store without having to deal with all sorts of manual issues that can come. All of our stuff is stitched together like in make files so we have a make file that has all of our commands that we want to run so it’s a release that will run the fastlane stuff. And in Jenkins I've taken the time to actually extract out the big long scripts we might have had set up before and have that be really one make command. That way we can run them locally on our machines and have the same environment locally on development as an RCI environment. Plus, eventually when we do get away from Jenkins we can move something to another and it's really simple to recreate those commands in whatever manifest GitLab CI we’ll use.
Leo: Have you started working with GitLab CI?
Jared: Not yet. No.
Leo: Okay.
Jared: How was your experience with it?
Leo: I really like it. Well, it was Travis first but Travis has had its issues Recently. I don't know if you've used Travis. But I do a lot of stuff with Swift Package Manager and Bitrise and Circle CI isn't really a good fit for that as far as where I'm at. So then I tend to use GitHub Actions quite a bit because it's free, it works on open source public repos, and it works great. But then I had some private projects and then that's where GitLab CI just worked perfectly. What I really like about it is I just bought a brand new M1 Macbook Air and so now I could take an old Macbook Pro and hook that up to GitLab CI and run it on there. And it's free basically so now I have my own little CI machine I could use to publish apps. Yeah, it's a really, really powerful GitLab. I cannot totally see why a lot of companies have moved a lot of their code over to GitLab because it's just so powerful.
Jared: Yeah. You could do something similar with GitHub as well. There's the actions runner that you can put on a Mac and hook that up to GitHub. I've started down that process a little bit. But every time I’d start doing something like that on the side I find that I get distracted from the thing I'm actually trying to do so I'm like no I get to keep focused on the app I'm trying to ship as opposed to the tooling. That sounds like a lot of fun to build up around it. Otherwise, I'll never ship anything.
Leo: Yeah. Well, that brings up a really good point. Because I think if there's anything us developers can run into it's over automating everything. How do you draw that line? Like I need to be careful because I'm trying to spend way too much time automating this and I'm spending hours automating it for something that honestly manually would only take me a few minutes to do every so often.
Jared: Yeah, it's definitely something that I don't realize upfront. It's only after I've spent a bunch of time into something that I'm like, “Should I really be doing this in the first place?” One example that recently comes to mind is a side project that I'm working on. I'm working on a new app that's Mac and iOS and I want to distribute betas for iOS. We have TestFlight. TestFlight is awesome. It's so good. On the Mac we have nothing. We have to roll it all ourselves or find some other distribution method, right? I went to go and integrate Sparkle in my app.
Leo: Yes, I’ve used Sparkle before.
Jared: Yeah, Sparkle is really cool but v1 only works with non-sandboxed apps and my app was sandboxed so I had to like… and v2 has no actual official distribution yet. You have to build it from source as far as I could tell. So trying to get the process of automating not just building a whole other variant signed by a developer ID through fastlane and then the notarizing process. Automating all of that is a pain. I'm hoping like every year we say this and it doesn't happen. It still gets increasingly close to TestFlight for the Mac. My end goal is to dump that entire part of my code base and just use TestFlight for the Mac when that comes out. Probably four or five hours into this I'm like instead of trying to automate everything, automate the stuff that makes sense. Give me the code signing keys through fastlane so I can do matches and all that good stuff. But actually just make the build in Xcode like a savage and upload and do this. Do everything just the Xcode way because that's actually just going to get me the app that I need at the end of the day.
Leo: Right. I use an app called Ulysses. I don't know if you're familiar with it for writing. And they have a beta and they were using Microsoft App Center to distribute beta.
Jared: Oh, that’s interesting.
Leo: There's a fastlane plug-in for App Center so that might be worth it. Sorry, now you might suck a lot of time into this after this recording but that might be something to look into because that's what they use to distribute their beta was App Center.
Jared: That's cool. Okay.
Leo: Yeah, do you think that they're going to come out with TestFlight for Mac OS? What do you think the technical challenge would be for that?
Jared: I mean, they have all the pieces in place. There's nothing that they don't have. I think that they need to build. I think they just need to have the want to. I think we've seen a lack of investment in the Mac app store on the whole compared to the iOS app store. It seems like every year there's some big new advancements in the iOS app store and the Mac app store might get a new coat of paint every now and then.
Leo: Do you think? I might go so far as to disagree because I think the Mac app store is pretty cool. There's a lot there. It's just that I forget about it. I don't think it's a matter of effort. I just think, “Oh right, there's a Mac app store.” I think I've used it more and more, especially with my m1 because I want to make sure that I use stuff in the app store. But they have articles. They have a lot of stuff. Whereas, honestly, the iOS app store I barely use that honestly. It's become really hard to find stuff on there.
Jared: Yeah, it's hard to find stuff on the Mac app store though too. The example I heard the other day on a podcast was someone said that they were searching for Excel and they got an app that has Excel's icon but it's like a bunch of templates or something that they paid $10 for. They thought they were getting Excel but they didn't get Excel. Stuff like that is not great. There's also a lot of big apps that just can't be in the app store like the sandboxing rule and that kind of thing. I get it to a certain extent but I think the visibility and you don't think about it that's on Apple. It seems like a sign of a lack of investment in it because the apps that you want aren't always in there and so you're more willing to go to their website because it's still kind of the default. As a Mac user, if you want to go find a new app or download something you go to the website of the app developer and you might buy it there. They might direct you to the app store because it's only going to be there. But on the whole I think the Mac app store does leave something to be desired for sure.
But to get back to the TestFlight question I don't know that there's any missing pieces there. They just need to want to do it. I hope that the merging of… Well, merging isn't the right word, but the unification of the platform architectures now that we've got Apple Silicon and iOS apps running on the Mac. I think and I hope people are going to start expecting TestFlight betas on the Mac for their iOS apps for instance and that can just like be a carryover and lead into Mac TestFlight proper. That's my hope.
Leo: Yeah, I agree.
Jared: I'm excited for WWDC. We'll see what they come up with but that's definitely on my wish list.
Leo: I wanted to talk a little bit more about other forms of automation you might use. Yeah, we talked about fastlane and XcodeGen. Which do you want to talk about next?
Jared: Those are the main couple things that I use on a day-to-day basis. I did mention oh… You know what's really cool that I've really been liking is Swift Package Manager and making swift's command line tools with argument parser. Have you used Swift argument parser before?
Leo: Yeah, I agree.
Jared: So good.
Leo: Like we said you have your own podcast Xcoders and I'm going to be on there in your next episode. We're going to talk a little bit more about automation and how much I like Swift Package Manager. But it sounds like you're doing some stuff with automation and Swift Package Manager and using the argument parser package which I talked about last year in one of my talks. What have you found really powerful with it?
Jared: It makes building command line apps super easy and if I combine that with another package called ShellOut by John Sundell then I can use that to glue together shell scripts essentially and build shell scripts without having to write Bash. And Bash sucks. It's super hard to work with and so that feels like it gives me superpowers in some ways because I can integrate everything I know about Swift and how to work with Swift on a day-to-day basis. And I get all the power from Bash scripts and use the shell to do whatever it is that I need to do. It’s really, really good.
Leo: Yeah, I've used ShellOut quite a bit by John. Like you said, there's a lot of environment variables and things you don't have access to if you're going to run through process or process info and [unclear] made that a lot easier. Like I said, I did a talk last year on argument parser and it's one of my favorite automated tools out there. What it does is it brings things codable and some of the new stuff with property wrappers and swift UI over to the command line. And it just makes it a lot easier to really build robust command line interfaces.
Jared: Yeah, you just build out your struct that is a command and implement it. It just works. And if you give it the wrong arguments it prints out a super helpful description of how you actually use this thing. It gives you everything you need to make a really amazing command line tool. Have you used it with swift-sh before?
Leo: No, because I think I just don't use swift-sh as much as I used to now that we can build executables pretty easily.
Jared: Yeah, I get that.
Leo: I went down the path of using swift-sh when I was helping Dave there with some Swift Package validation for Swift Package Index. And then, I ended up saying screw this I'm just going to build that executable. I think it was a tool of its time. But I think now it's just so much easier to just write the executable and compile it I guess or even just run Swift, Swift run.
Jared: Well, swift-sh does that but just under the covers, right. It still gives you the executable. It still gives you the Swift package at the end of the day. But all you have to check is your one file not as opposed to like the entire structure of a package. So if you just write one script…
Leo: That makes total sense. I think if you have something fairly simple and you can just put it all in one file then it makes total sense.
Jared: Yeah, totally. If it's going to get bigger and merit multiple files then absolutely make a package out of it. But if you just want one script file then it works really well and it works really well with argument parser. It’s super good.
Leo: Yeah, totally. I think that was the situation I ran into is my file was getting a bit longer.
Jared: Yeah. That’s why it's got the helpful eject command because you can eject your script into a package and it'll just give you where you used to have one Swift file it will give you the folder of your Swift package with a proper manifest and everything.
Leo: That's awesome. Yeah, it's a really powerful tool.
Jared: Super good.
Leo: I highly recommend people check it out. What other tools have you used when it comes to automation?
Jared: I think the big thing that I've used like I mentioned before is Makefiles. Makefiles are this kind of product of the older era and older generation to build systems and all of my commands start with phony at the top. That's another trick I learned at Lyft. But you can use these commands where you type make and then they call them rules, make and then some rule and then a colon, and then you just got a little script you can embed in line to call other scripts, to call other tools. And everything after the colon on the same line are other rules that will be invoked before actually calling your script. So for instance, to make our project through Tuist at Zulily we have a command called make project. And that will then ensure that stuff like Tuist is installed and configured properly. We have a follow-up script that's written in swift-sh so it makes sure that swift-sh is installed and configured. And that way once you get to where you're generating your project and running your cleanup script everything is already done for you. You can chain those commands together to make some really powerful automations and it's really nice.
Leo: I think a lot of folks think Makefiles are just for your C or C++ project but it's really about managing 100 dependencies and running the commands in the correct order. That's the way I see it. Yeah, I'm in the same boat where I found myself, you know, what would be really good is a big file because then I don't have to manage all these dependencies and things like that. Yeah, that’s awesome.
Jared: I know that Ruby has a rake which is their Ruby equivalent of make I think. And that probably has less of the, “This is for C folks stigma”, than Makefiles do. I've wanted to make one in Swift that I would call ‘sake’, substitute the m for the s and there you go. And then you have your sake file. It's like I've got the branding all there. I just haven't actually written the thing.
Leo: It's so funny you're talking about branding. I feel that's almost the funniest part: it's trying to come up with names for some of these projects. It is like, “Okay is the domain available? What has to do with Swift? Yeah, I’ll replace the m with s.” Well, the other project I was working on in Soto was the same story. They replaced Boto I think was either the Go or the Ruby thing for AWS. They replaced it with an s for Soto for Swift. And I was like oh that makes sense.
Jared: I didn't know that was the origin of that.
Leo: Yeah. We talked about it in a previous episode and luckily Adam followed up and let me know on Twitter. So one of the big challenges with automation is the cost. I found a way around by using my old Mac. But to do a lot of this stuff you need Mac OS.
Jared: Yeah.
Leo: How do you get around that? I guess you just find your own Mac. Have you ever worked with something like MacStadium? What have you seen as some of the big challenges with requiring Mac OS essentially?
Jared: I would love to work with MacStadium or some co-located Mac host someday. I know Amazon has rolled out their Macs in AWS that are really expensive but a good option for [unclear] especially if you've already got AWS in your organization. At Zulily, we host two Mac minis at the moment, one is a 2014 that runs our Jenkins server and one is a 2018 that's our runner. Another one of the automation projects I have ahead of me is to make some Ansible Playbooks so that we can have the Mac, the runner, configured as we want to and then expand that fleet to add a couple more.
Leo: Take a step back because I don't know what that means. What's Ansible?
Jared: Ansible. There are tools like that. Another one I've heard of is Chef. I haven't used either one. Full disclosure so I don't know how this is all going to play out but the idea is that you can have one central repository that defines what Mac OS version are you running, what Xcode version are you running, what's your environment overall configured and then apply that to a fleet of machines.
Leo: Got you.
Jared: As Xcode 12.5 beta next rolls out we could add that to our Ansible Playbook, roll it out to our Mac minis, and it will download, unzip, and move Xcode beta into the proper place automatically.
Leo: That's awesome.
Jared: Yeah. I'm looking forward to getting that done. But we host those Mac minis in our building at Zulily. Personally, while I'm setting things up in my environment like with fastlane to do automation and I've got another Mac mini at home that can do some of that continuous integration work. I haven't gone through the actual process of saying I’m going to set up one that I push to main my mac mini will make a new build and push it to TestFlight automatically. I haven't gotten that part wired up yet but the plumbing is largely in place once I d o get to the point where I can invest that time.
Leo: One of the powerful things I've found is using fastlane matches to manage the certificates. That was a big help. But with a lot of these things with GitLab runner it's just not super easy to get set up on Mac OS. Also, you run into the issue of you can't do docker. I did find a docker OSX project I want to play around with when I have spare time whenever that happens. I'll provide the link to the show notes.
Jared: How does that work?
Leo: Yeah, I'd be really curious about that because what I've found is that as somebody who builds Mac apps, I don't have the ability to reset the simulator. And if you know what I mean I can't just go like, “Oh, here Xcode try this out on Catalina. Here. Try this out on Big Sur.” Whereas, with iOS we just have this nice ability of getting any model iPhone and just testing it out. That's one of the biggest challenges with Mac OS development is not having that ability to test different environments.
Jared: Yeah. I guess that's where I’m at this point somewhat fortunate in that my Mac app is brand new and so I'm just building it against Big Sur and I don't have to worry about backwards compatibility yet.
Leo: I’m in the same boat. Yeah, that's what I’m doing. I’m doing Swift UI documents. Sorry, it's only going to work on Big Sur. Deal with it.
Jared: Yeah. I don’t know what the alternative for supporting old Mac versions is beyond either somehow automating VMware virtualized instances which is going to be super slow because Mac OS has never been virtualized well. Or just find old machines on eBay or Craigslist or whatever and just keep old Macs with old versions.
Leo: That's exactly what it is. Yeah. I mean, if you're that serious about supporting old versions you probably could spend the money on it.
Jared: Yeah, totally.
Leo: But there's no easy way to do it. Maybe, who knows, maybe with the m1s they can make that easier. I don't know. Not a bit. Not with Catalina but at least Big Sur going forward. Maybe they can be like, “Oh yeah, we can run a virtual Mac OS environment for Big Sur in five years”, or something like that. Because you essentially could run like an iPhone app so I would assume it's the same idea. I don’t know.
Jared: I mean, you're still needing to virtualize older versions of Mac OS. They did add the Hypervisor framework fairly recently so maybe that could unlock something there as well. I don’t know. Then there’s the licensing thing. Apple doesn't want to license Mac OS for running in lots of different environments like that. Maybe this is another pie in the sky thing. But that is something that comes from Buddybuild acquisition which is Buddybuild getting shut down as a CI provider pretty soon. I think there's some hope that's going to…
Leo: Mean something in a few months.
Jared: Yeah, exactly. That those flowers will die and the seeds that remain will flower their new Apple CI system which would be pretty cool to see what they come up with.
Leo: Yeah, exactly like that workflow idea right. It becomes shortcuts and it's amazing. Well, Jared, I want to continue this conversation but I think you want to ask me some more questions about Swift Package Manager automation and server side stuff. Okay, okay so where can people find your podcast?
Jared: Yeah, I run the Xcoders Community Podcast. You can find that at xcoders.org and that's representing the Seattle, Redmond, and Vancouver Xcoder developer groups.
Leo: Cool. So we'll post a link to this next part of the episode on Xcoders in the show notes below. Thank you so much, Jared, for coming on. Where can people find you online?
Jared: I'm on Twitter @jsorge. My website is jsorge.net.
Leo: Awesome. People can look in the show notes if they want to hear the rest of this conversation on Xcoders. I'm going to be talking more about Vapor server side development automation, Swift Package Manager, and tool automation things like that so you definitely want to check that next part in the show notes. Thank you so much for joining me for this episode. If you really enjoyed it, I would love for you to take some time and post a review to Apple Podcast. Google Podcast, Spotify, or Amazon. People can find me on Twitter @leogdion. My company is Bright Digit. Thank you so much for joining us for this episode and I look forward to listening to the next part of this conversation on Xcoders.
Jared: Thanks, Leo.
Leo: Thank you.